﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Objects;
using System.Linq;
using System.Threading;
using System.Web;
using System.Xml;
using CloudPms.Common.Utils;
using CloudPms.Entity.Entities;

namespace CloudPms.Domain.Repository
{
    /// <summary>
    /// 数据库存储提供服务
    /// <para>--------------------------</para>
    /// <para>@Author: cnalexi@gmail.com</para> 
    /// <para>@Create: 2012/9/29</para>  
    /// </summary>
    public sealed class DbContextService
    {
        private static volatile IList<string> _baseDbTypeCache;

        private static volatile IList<BusinessConnection> _businessConnections;

        private static readonly object lockThis = new object();

        public static ObjectContext GetObjectContext(string hotelId, Type type)
        {
            var dbContext = GetDbContext(hotelId, type);

            return ((IObjectContextAdapter)dbContext).ObjectContext;
        }

        public static ObjectContext GetObjectContext(string hotelId, Type type, bool isHistory)
        {
            var dbContext = GetDbContext(hotelId, type, isHistory);

            return ((IObjectContextAdapter)dbContext).ObjectContext;
        }

        /// <summary>
        /// 获取数据库访问上下文
        /// </summary>
        /// <param name="hotelId">酒店编号</param>
        /// <param name="type">类型</param>
        /// <returns>DbContext:AutoDetectChangesEnabled=false</returns>
        public static DbContext GetDbContext(string hotelId, Type type)
        {
            //根据type判断要不要加载主库
            DbContext context = InBaseDb(type.Name)
                ? (DbContext)new PmsBaseContext()
                : (DbContext)new BusinessContext(GetConnectionString(hotelId));

            ////启用延迟加载
            //context.Configuration.LazyLoadingEnabled = true;

            ////禁用代理创建对象
            //context.Configuration.ProxyCreationEnabled = false;
           
            context.Configuration.AutoDetectChangesEnabled = false;

            return context;
        }

        /// <summary>
        /// 获取数据库访问上下文
        /// </summary>
        /// <param name="hotelId">酒店编号</param>
        /// <param name="type">类型</param>
        /// <param name="isHistory">是否查询历史库</param>
        /// <returns>DbContext:AutoDetectChangesEnabled=false</returns>
        public static DbContext GetDbContext(string hotelId, Type type,bool isHistory)
        {
            if (!isHistory)
            {
                return GetDbContext(hotelId, type);
            }
            
            DbContext context = InBaseDb(type.Name)
                ? (DbContext)new PmsBaseContext()
                : (DbContext)new BusinessContext(GetHistoryConnectionString(hotelId));

            context.Configuration.AutoDetectChangesEnabled = false;

            return context;
        }

        public static IList<string> GetAllConnectionString()
        {
            if (_businessConnections == null)
            {
                lock (lockThis)
                {
                    if (_businessConnections == null)
                    {
                        _businessConnections = GetConnections();

                        Thread.MemoryBarrier();
                    }
                }
            }

            return _businessConnections.Select(b => b.ConnectionString).Distinct().ToList();
        }

        private static IList<BusinessConnection> GetConnections()
        {
            using (var context = new PmsBaseContext())
            {
                var connections = context.Set<HotelBizDay>()
                    .Where(b => !string.IsNullOrEmpty(b.ConnectionString))
                    .Select(b => new BusinessConnection { HotelID = b.ID, ConnectionString = b.ConnectionString })
                    .ToList();

                return connections;
            }
        }

        private static string GetHistoryConnectionString(string hotelId)
        {
            //获取HISTORY列表 配置历史库列表
            //酒店对应的历史库连接

            string conn = hotelId == "" ? "HAHANoHistory" : "HisBizDb01";

            return conn;

        }

        private static string GetConnectionString(string hotelId)
        {
            if (_businessConnections == null)
            {
                lock (lockThis)
                {
                    if (_businessConnections == null)
                    {
                        _businessConnections = GetConnections();

                        Thread.MemoryBarrier();
                    }
                }
            }

            if (_businessConnections == null)
            {
                throw new ArgumentNullException(ErrorCode.BASE_NO_CONNECTION);
            }

            BusinessConnection connection = _businessConnections.SingleOrDefault(s => s.HotelID == hotelId);

            if (connection == null)
            {
                _businessConnections = GetConnections();

                connection = _businessConnections.SingleOrDefault(s => s.HotelID == hotelId);
            }

            if (connection == null)
            {
                throw new ArgumentNullException(string.Format("数据库连接建立失败，请检查酒店ID:{0} 是否已经成功初始化", hotelId));
            }

            return connection.ConnectionString;

        }

        private static IEnumerable<string> GetBaseDbTypeCache()
        {
            if (_baseDbTypeCache == null)
            {
                lock (lockThis)
                {
                    if (_baseDbTypeCache == null)
                    {
                        _baseDbTypeCache = GetBaseDbTypes();

                        Thread.MemoryBarrier();
                    }
                }
            }
            return _baseDbTypeCache;
        }

        private static bool InBaseDb(string typeName)
        {
            //Debug.Assert(_baseDbTypeCache != null, "_baseDbTypeCache != null");

            return GetBaseDbTypeCache().Contains(typeName);
        }

        private static IList<string> GetBaseDbTypes()
        {
            XmlDocument doc = new XmlDocument();

            string path = GetRootPath() + @"BaseDBType.xml";

            doc.Load(path);

            XmlNodeList baseDbTypeNodes = doc.SelectNodes("/BaseDBType/type");

            var baseDbTypes = (from XmlNode node in baseDbTypeNodes
                              select node.Attributes["name"].Value).ToList();

            //var baseDbTypes = from XmlNode node in baseDbTypeNodes
            //                  let xmlAttributeCollection = node.Attributes
            //                  where xmlAttributeCollection != null
            //                  select xmlAttributeCollection["name"].Value;

            return baseDbTypes;
        }

        public static string GetRootPath()
        {
            string root = System.Web.Hosting.HostingEnvironment.MapPath("~") != null
                ? System.Web.Hosting.HostingEnvironment.MapPath("~") + @"\bin\"
                : string.Empty;

            if (string.IsNullOrEmpty(root))
            {
                root = (HttpContext.Current != null)
                              ? HttpContext.Current.Request.MapPath("~") + @"\bin\"
                              : string.Empty;
            }
            return root;
        }
    }
}
